// tune.pde - represents a series of notes from several voices spread out in time

/////////////////////////////////////////////////////////////
//globals for tune generator



//#define LOG_TUNE

unsigned short int tuneListMidiNote[TUNE_LIST_SIZE]; // MIDI note number
unsigned char tuneListVolume[TUNE_LIST_SIZE];  // note volume
unsigned int tuneListEnvelopeDelta[TUNE_LIST_SIZE];  

unsigned int tuneListBeat[TUNE_LIST_SIZE];       // beat to start note on
unsigned int tuneListChannel[TUNE_LIST_SIZE];      // voice (0-CHANNELS) to use

unsigned short int tuneVoice[CHANNELS];

//unsigned short int tuneEnvelopeDelta[CHANNELS];
// Envelope Deltas for the notes generated by the tune sequence

unsigned short int tuneVibratoPercent[CHANNELS];
// Vibrato Percents for the notes generated by the tune sequence
unsigned short int tuneEnvelope[CHANNELS];

long tuneNextBeatTime = 0; // time in millis to do the next beat
int tuneNextBeat = 0; // beat value of the next note to play
int tuneNextListIndex = 0; // index into note list

long tuneBeatInterval = 500; // millisecs per beat
int tuneBarLength = 4;
int tuneNoteCount = 0;

void setupTune() // called from setup - clean up our data structures
{
    tuneBeatInterval = 500;
    tuneNextBeatTime = 0;
    
    tuneDelete();
}

void tuneDelete() // destroy the existing tune
{
  tuneNoteCount = 0;
  tuneNextListIndex = 0;
  tuneNextBeat = 0;
  
}

void tuneAddNote( int noteNumber,unsigned char  volume, unsigned int envelopeDelta, int beat, int channel )
{
  if(  tuneNoteCount >= TUNE_LIST_SIZE )
    return;
    
   if( channel >= CHANNELS )
     return;
     
  tuneListMidiNote[ tuneNoteCount] = noteNumber; // MIDI note number
  tuneListVolume[ tuneNoteCount ] = volume;
  tuneListEnvelopeDelta[ tuneNoteCount ] = envelopeDelta;
  tuneListBeat[ tuneNoteCount] = beat;       // beat to start note on
  tuneListChannel[ tuneNoteCount ] = channel;
   tuneNoteCount++;
}

int progressTune() // called from loop() repeatedly - work out if a note is due, and start it
{
  long now = millis();
  
  if( now < tuneNextBeatTime )
    return 0;

   // find all the notes in the list which are due at this beat and start them
   while( tuneNextListIndex < tuneNoteCount && tuneListBeat[ tuneNextListIndex ] <= tuneNextBeat )
   {
      
     logTuneProgress();

      
      int channel = tuneListChannel[ tuneNextListIndex ];
      
      startNote (channel, 
                  tuneListMidiNote[ tuneNextListIndex ], 
                  tuneListVolume[ tuneNextListIndex ],
                  tuneVoice[ channel ], 
                  tuneListEnvelopeDelta[tuneNextListIndex], tuneEnvelope[channel], 7, tuneVibratoPercent[channel]);
 
      tuneNextListIndex ++;
      
   }
    
  tuneNextBeat ++;  
  tuneNextBeatTime = now + tuneBeatInterval;
  
  
  if( tuneNextListIndex >= tuneNoteCount ) // start again
  {
    tuneNextListIndex = 0;
    tuneNextBeat = 0;
  }
  
  return tuneNextBeat%tuneBarLength == 0; // bar just begun!
}

void logTuneProgress()
{
      #ifdef DO_LOGGING
      #ifdef LOG_TUNE
      Serial.print ("progressTune - next index: ");
      Serial.print (tuneNextListIndex, DEC); 
      Serial.print ("\n");
      
      Serial.print ("beat: ");
      Serial.print (tuneListBeat[ tuneNextListIndex ], DEC); 
      Serial.print ("\n");

      Serial.print ("midi note num: ");
      Serial.print (tuneListMidiNote[ tuneNextListIndex ], DEC); 
      Serial.print ("\n");
      
      Serial.print ("channel: ");
      Serial.print (tuneListChannel[ tuneNextListIndex ], DEC); 
      Serial.print ("\n");
      #endif
      #endif
}
      
void tuneSetBeatInterval( int time )
{
  tuneBeatInterval = time;
}

void tuneSetBarLength( int barLength )
{
  tuneBarLength = barLength;
}



/* tuneSetVoice --- set the voice to be used for a given tune generator */

void tuneSetVoice (unsigned short int channel, unsigned short int voice)
{
  if ((channel >= 0) && (channel < CHANNELS))
    tuneVoice[channel] = voice;
}


/* tuneSetVolumeDelta --- set the volume delta to be used for a given tune generator */
/*
void tuneSetEnvelopeDelta (unsigned short int channel, unsigned short int envelopeDelta)
{
  if ((channel >= 0) && (channel < CHANNELS))
    tuneEnvelopeDelta[channel] = envelopeDelta;
}
*/

/* tuneSetVibratoPercent --- set the vibrato percent to be used for a given tune generator */

void tuneSetVibratoPercent (unsigned short int channel, unsigned short int vibratoPercent)
{
  if ((channel >= 0) && (channel < CHANNELS))
    tuneVibratoPercent[channel] = vibratoPercent;
}


/* tuneSetEnvelope --- set the envelope to be used for a given tune generator */

void tuneSetEnvelope (unsigned short int channel, unsigned short int envelope)
{
  if ((channel >= 0) && (channel < CHANNELS))
    tuneEnvelope[channel] = envelope;
}


